package one.stand.config;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import one.stand.handler.ChildHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author Administrator
 */
@Configuration
public class NettyConfig {
    /**
     * 缓存字节数
     */
    @Value("${netty.backlog}")
    private int backlog;
    /**
     * BOSS处理客户端连接线程数
     */
    @Value("${netty.bossThread}")
    private int bossCount;
    @Autowired
    private ChildHandler childHandler;
    /**
     * 是否保持长连接
     */
    @Value("${netty.keepalive}")
    private boolean keepAlive;
    private Logger log = LoggerFactory.getLogger(NettyConfig.class);
    /**
     * 是否延迟（这里使用不延迟立即发送）
     */
    @Value("${netty.nodelay}")
    private boolean nodelay;
    /**
     * tcp端口
     */
    @Value("${netty.port}")
    private int tcpPort;
    /**
     * Worker处理读写线程数
     */
    @Value("${netty.workerThread}")
    private int workerCount;

    /**
     * Necessary to make the Value annotations work.
     *
     * @return
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {

        return new PropertySourcesPlaceholderConfigurer();
    }

    /**
     * 生产辅助工具类交给Srping
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    @Bean(name = "serverBootstrap")
    public ServerBootstrap bootstrap() {

        /* 创建bootstrap辅助工具类，用于服务器通道的一系列配置 */
        ServerBootstrap b = new ServerBootstrap();
        /* 绑定两条线程 */
        b.group(bossGroup(), workerGroup());
        /* 指定NIO模式 */
        b.channel(NioServerSocketChannel.class);
        /* 不是默认的，可以重复利用之前分配的内存空间。 */
        b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        b.childHandler(childHandler);
        Map<ChannelOption<?>, Object> tcpChannelOptions = tcpChannelOptions();
        Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
        for (ChannelOption option : keySet) {
            b.option(option, tcpChannelOptions.get(option));
        }
        log.info("TCP BIND OK.....");
        return b;
    }

    /**
     * BOSS处理客户端连接
     */
    @Bean(name = "bossGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup bossGroup() {

        return new NioEventLoopGroup(bossCount);
    }

    /**
     * Worker处理读写
     */
    @Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup workerGroup() {
        return new NioEventLoopGroup(workerCount);
    }

    @Bean(name = "tcpChannelOptions")
    public Map<ChannelOption<?>, Object> tcpChannelOptions() {
        log.info("是否保持连接：" + keepAlive);
        log.info("字节缓冲数量：" + backlog);
        log.info("是否立即发送消息：" + nodelay);
        Map<ChannelOption<?>, Object> options = new HashMap<>(3);
        /* 是否保持连接 */
        options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
        /* 字节缓冲数量 */
        options.put(ChannelOption.SO_BACKLOG, backlog);
        /* 是否立即发送消息 */
        options.put(ChannelOption.TCP_NODELAY, nodelay);
        return options;
    }

    /**
     * 生产TCP服务器信息交给Spring容器
     *
     * @return
     */
    @Bean(name = "tcpSocketAddress")
    public InetSocketAddress tcpPort() {

        return new InetSocketAddress(tcpPort);
    }
}
